<?php

class Model_Mapper_Categories extends Model {
	
	protected $_dbTable;
	private static $instance;
	
	public static function newInstance() {
		if (! self::$instance instanceof self) {
			self::$instance = new self ();
		}
		return self::$instance;
	}
	
	public function setDbTable($dbTable) {
		if (is_string ( $dbTable )) {
			$dbTable = new $dbTable ();
		}
		if (! $dbTable instanceof Zend_Db_Table_Abstract) {
			throw new Exception ( 'Invalid table data gateway provided' );
		}
		$this->_dbTable = $dbTable;
		return $this;
	}
	
	public function getDbTable() {
		if (null === $this->_dbTable) {
			$this->setDbTable ( 'Model_Table_Categories' );
		}
		return $this->_dbTable;
	}
	
	public function save(Model_Categories $categories) {
		$data = array ('parent_id' => $categories->getParent_id (), 'expiration_days' => $categories->getExpiration_days (), 'position' => $categories->getPosition (), 'enabled' => $categories->getEnabled (), 'icon' => $categories->getIcon (), 'image' => $categories->getImage (), 'category_order' => $categories->getCategory_order (), 'name' => $categories->getName (), 'description' => $categories->getDescription (), 'slug' => $categories->getSlug () );
		$key = $this->getDbTable ()->getPrimaryKey ();
		$method = 'get' . ucfirst ( $key );
		$val = $categories->$method ();
		if ($val == null) {
			unset ( $data [$key] );
			$categories->setCategory_id ( $this->getDbTable ()->insert ( $data ) );
		} else {
			$this->getDbTable ()->update ( $data, array ($key . ' = ?' => $val ) );
		}
	}
	
	/*
	 * *************************************************************
	 * Gets URI for the category
	 * *************************************************************
	 * @return string (uri)
	 * @args Either instance of Model_categories or category_id
	 */
	
	function getURI($category, $location = true) {
		if ($category == '') {
			throw new Exception ( 'Invalid Category Provided.' );
		}
		$category_id = '';
		if ($category instanceof Model_Categories) {
			$category_id = $category->getCategory_id ();
		} else {
			$category_id = $category;
		}
		
		$tree = $this->toRoot ( $category_id );
		if ($tree) {
			$links = array ();
			foreach ( $tree as $item ) {
				$links [] = $item->getSlug ();
			}
			$link = site_url ();
			if (Params::getParam ( 'location' ) && $location) {
				$loc = Params::getParam ( 'location' );
				$link .= $loc->getSlug ();
			}
			$link .= '/' . implode ( '/', array_reverse ( $links ) ) . '/';
			return sanitizeURI ( $link );
		} else {
			return '';
		}
	}
	
	function getSectionURI($category, $location = true) {
		if ($category == '') {
			throw new Exception ( 'Invalid Category Provided.' );
		}
		$category_id = '';
		if ($category instanceof Model_Categories) {
			$category_id = $category->getCategory_id ();
		} else {
			$category_id = $category;
		}
		
		$tree = $this->toRoot ( $category_id );
		if ($tree) {
			$links = array ();
			foreach ( $tree as $item ) {
				$links [] = $item->getSlug ();
			}
			$link = '';
			$link .= '/' . implode ( '/', array_reverse ( $links ) ) . '/';
			return sanitizeURI ( $link );
		} else {
			return '';
		}
	}
	
	public function hasItems($category) {
		if ($category == '') {
			throw new Exception ( 'Invalid Category Provided.' );
		}
		if (! $category instanceof Model_Categories) {
			$category = Model_Mapper_Categories::newInstance ()->getByID ( $category );
		}
		
		$items = Model_Mapper_Items::newInstance ()->getByCategory ( $category, true );
		
		if ($items) {
			return true;
		}
		return false;
	}
	
	public function getItems($category, $recursive = false, $args = array(),$location='') {
		if ($category == '') {
			throw new Exception ( 'Invalid Category Provided.' );
		}
		if (! $category instanceof Model_Categories) {
			$category = Model_Mapper_Categories::newInstance ()->getByID ( $category );
		}
		
		if ($recursive) {
			$items = Model_Mapper_Items::newInstance ()->getByCategory ( $category, false, true, $args );
		} else {
			$items = Model_Mapper_Items::newInstance ()->getByCategory ( $category, false, false, $args );
		}
		
		if ($items) {
			return $items;
		} else {
			return array ();
		}
	}
	
	public function getItemCount($category, $recursive = true) {
		if ($category == '') {
			throw new Exception ( 'Invalid Category Provided.' );
		}
		if (! $category instanceof Model_Categories) {
			$category = Model_Mapper_Categories::newInstance ()->getByID ( $category );
		}
		$args=array();
		if (Params::getParam ( 'location' ) ) {
				$loc = Params::getParam ( 'location' );
				$args['location_id']=$loc->getLocation_id();
			}
		
		if ($recursive) {
			$items = Model_Mapper_Items::newInstance ()->getByCategory ( $category, true, true,$args );
		} else {
			$items = Model_Mapper_Items::newInstance ()->getByCategory( $category, true,false,$args );
		}
		
		return count ( $items );
	
	}
	
	public function increaseOrder($category) {
		if ($category == '') {
			throw new Exception ( 'Invalid Category Provided.' );
		}
		$category_id = '';
		if (! $category instanceof Model_Categories) {
			$category = $this->getByID ( $category );
		}
		
		$category->setCategory_order ( $category->getCategory_order () + 3 ); // increase current order value by 3
		$category->save ();
		$this->order ();
	}
	
	public function decreaseOrder($category) {
		if ($category == '') {
			throw new Exception ( 'Invalid Category Provided.' );
		}
		$category_id = '';
		if (! $category instanceof Model_Categories) {
			$category = $this->getByID ( $category );
		}
		
		$category->setCategory_order ( $category->getCategory_order () - 3 ); // decrease current order value by 3
		$category->save ();
		// now process category order
		$this->order ();
	}
	
	public function order() {
		$items = $this->getAll ( '', 'category_order ASC' );
		$count = 2;
		foreach ( $items as $item ) {
			$item->setCategory_order ( $count );
			$item->save ();
			$count ++;
			$count ++;
		}
	}
	
	/*
	 * ************************************
	 * Retrieve Category by Slug
	 * ************************************
	 */
	
	public function getBySlug($slug) {
		if ($slug == '') {
			throw new Exception ( 'Invalid Category Provided.' );
		}
		$table = $this->getDbTable ();
		$select = $table->select ();
		$select->from ( $table );
		$select->where ( 'slug=?', $slug );
		$result = $this->extend ( $table->fetchAll ( $select ) );
		if ($result) {
			return $result [0];
		} else {
			return array ();
		}
	}
	
	/*
	 * **********************************************
	 * CHECK IF CATEGORY EXISTS BASED ON PARAMETERS
	 * **********************************************
	 */
	public function exists($args) {
		if (! is_array ( $args )) {
			throw new Exception ( 'Invalid Argument Array Provided' );
		}
		
		$table = $this->getDbTable ();
		$select = $table->select ();
		$select->from ( $table );
		foreach ( $args as $key => $value ) {
			$select->where ( $key . '=?', $value );
		}
		$result = $table->fetchAll ( $select );
		if ($result) {
			return true;
		} else {
			return false;
		}
	}
	
	/*
	 * *******************************
	 * GET CATEGORIES BY CONDITION
	 * *******************************
	 */
	
	function getByCondition(array $args, $array = false) {
		if (! is_array ( $args )) {
			throw new Exception ( 'Invalid Argument Array Provided' );
		}
		$table = $this->getDbTable ();
		$select = $table->select ();
		$select->from ( $table );
		foreach ( $args as $key => $value ) {
			$select->where ( $key . '=?', $value );
		}
		
		$result = $table->fetchAll ( $select );
		$result = $this->extend ( $result );
		if ($result) {
			if ($array) {
				foreach ( $result as $key => $item ) {
					$result [$key] = $item->toArray ();
				}
			}
			
			return $result;
		
		} else {
			return array ();
		}
	}
	
	/*
	 * ***************************************
	 * Get top level Categories
	 * ***************************************
	 */
	
	public function getTopCategories($array = false, $enabled = true) {
		$args = array ('parent_id' => 0 );
		if ($enabled) {
			$args ['enabled'] = 1;
		}
		if ($array) {
			return $this->getByCondition ( $args, true );
		}
		return $this->getByCondition ( $args );
	}
	
	public function getSubCategories($category, $array = false, $recursive = false) {
		if ($category == '') {
			throw new Exception ( 'Invalid Category Provided.' );
		}
		$category_id = '';
		if ($category instanceof Model_Categories) {
			$category_id = $category->getCategory_id ();
		} else {
			$category_id = $category;
		}
		
		if ($recursive) {
			$items = array ();
			$subs = $this->_getSubCategories ( $category_id, true );
			foreach ( $subs as $cat ) {
				$items [] = $cat;
				$temp = $this->getSubCategories ( $cat ['category_id'], true );
				if ($temp) {
					$items = array_merge ( $items, $temp );
				}
			}
			return $items;
		} else {
			return $this->_getSubCategories ( $category_id, $array );
		}
	
	}
	
	private function _getSubCategories($category, $array = false) {
		if ($category == '') {
			throw new Exception ( 'Invalid Category Provided.' );
		}
		$category_id = '';
		if ($category instanceof Model_Categories) {
			$category_id = $category->getCategory_id ();
		} else {
			$category_id = $category;
		}
		if ($array) {
			$args = array ('parent_id' => $category_id );
			return $this->getByCondition ( $args, true );
		} else {
			$args = array ('parent_id' => $category_id );
			return $this->getByCondition ( $args, false );
		}
	
	}
	
	function hasSubCateogries($category) {
		if ($category == '') {
			throw new Exception ( 'Invalid Category Provided.' );
		}
		$category_id = '';
		if ($category instanceof Model_Categories) {
			$category_id = $category->getCategory_id ();
		} else {
			$category_id = $category;
		}
		$items = $this->_getSubCategories ( $category, true );
		if ($items) {
			return true;
		} else {
			return false;
		}
	}
	
	public function tree() {
		$all = $this->getTopCategories ();
		$items = array ();
		if ($all) {
			foreach ( $all as $cat ) {
				$items [] = $this->_toTree ( $cat->getCategory_id (), 0 );
			}
		}
		
		return $items;
	}
	
	public function toTree($category) {
		return $items = $this->_toTree ( $category );
	}
	
	public function getRoot($category) {
		if ($category == '') {
			throw new Exception ( 'Invalid Category Provided.' );
		}
		$category_id = '';
		if ($category instanceof Model_Categories) {
			$category_id = $category->getCategory_id ();
		} else {
			$category_id = $category;
		}
		$result = $this->getByID ( $category_id );
		if ($result) {
			while ( $result->getParent_id () > 0 ) {
				$result = $this->getByID ( $result->getParent_id () );
			}
		}
		return $result;
	}
	
	private function _toTree($category, $level = 0) {
		if ($category == '') {
			throw new Exception ( 'Invalid Category Provided.' );
		}
		
		$category_id = '';
		if ($category instanceof Model_Categories) {
			$category_id = $category->getCategory_id ();
		} else {
			$category_id = $category;
		}
		$item = $this->getByID ( $category_id );
		$item = $item->toArray ();
		$result = Model_Mapper_Categories::newInstance ()->getSubCategories ( $item ['category_id'] );
		$item ['count'] = count ( $result );
		$item ['level'] = $level;
		if ($this->hasSubCateogries ( $category )) {
			$subs = $this->_getSubCategories ( $category, true );
			foreach ( $subs as $cat ) {
				$item ['child'] [] = $this->_toTree ( $cat ['category_id'], $level + 1 );
			}
		
		}
		
		return $item;
	}
	
	/*
	 * **************************************
	 * Gets Image URI of given category
	 * **************************************
	 * @return string
	 * @argument: Model_Categories or category_id
	 */
	
	public function getImageURI($category) {
		if ($category == '') {
			throw new Exception ( 'Invalid Category Provided.' );
		}
		$category_id = '';
		if (! $category instanceof Model_Categories) {
			$category = $this->getByID ( $category );
		}
		
		$image = $category->getImage ();
		if ($image != '') {
			$uri = content_url () . 'category_images/' . $image;
			return sanitizeURI ( $uri );
		} else {
			return '';
		}
	}
	public function getImagePath($category) {
		if ($category == '') {
			throw new Exception ( 'Invalid Category Provided.' );
		}
		$category_id = '';
		if (! $category instanceof Model_Categories) {
			$category = $this->getByID ( $category );
		}
		$image = $category->getImage ();
		if ($image == '') {
			return '';
		}
		return content_path () . 'category_images' . DS . $image;
	
	}
	
	public function deleteImage($category, $deleteFile = false) {
		if ($category == '') {
			throw new Exception ( 'Invalid Category Provided.' );
		}
		$category_id = '';
		if (! $category instanceof Model_Categories) {
			$category = $this->getByID ( $category );
		}
		$category->setImage ( '' );
		if ($deleteFile) {
			$path = $category->getImagePath ();
			@unlink ( $path );
		}
		$category->save ();
	}
	
	public function toRoot($category) {
		if ($category == '') {
			throw new Exception ( 'Invalid Category Provided.' );
		}
		$category_id = '';
		if ($category instanceof Model_Categories) {
			$category_id = $category->getCategory_id ();
		} else {
			$category_id = $category;
		}
		
		$result = $this->getByID ( $category_id );
		$tree = array ();
		
		if ($result) {
			$tree [] = $result;
			while ( $result->getParent_id () > 0 ) {
				$result = $this->getByID ( $result->getParent_id () );
				$tree [] = $result;
			}
		}
		return $tree;
	}
	
	public function extend($args) {
		$items = array ();
		if ($args) {
			foreach ( $args as $arg ) {
				if (is_object ( $arg )) {
					$arg = $arg->toArray ();
				}
				$item = new Model_Categories ( $arg );
				$items [] = $item;
			}
		}
		return $items;
	}
	
	public function lastInsertID() {
		return $this->getDbTable ()->getAdapter ()->lastInsertId ();
	}
	
	public function beginTransaction() {
		$this->getDbTable ()->getAdapter ()->beginTransaction ();
	}
	
	public function commit() {
		$this->getDbTable ()->getAdapter ()->commit ();
	}
	
	public function rollBack() {
		$this->getDbTable ()->getAdapter ()->rollBack ();
	}
	
	public function getAll($enabled = false, $orderby = '') {
		$table = $this->getDbTable ();
		$select = $table->select ();
		$select->from ( $this->getDbTable () );
		if ($enabled) {
			$select->where ( 'enabled=?', 1 );
		}
		if ($orderby == '') {
			$orderby = 'name ASC';
		}
		$select->order ( $orderby );
		return $this->extend ( $table->fetchAll ( $select ) );
	}
	
	public function getByID($id) {
		if ($id == '') {
			throw new Exception ( 'Invalid ID Provided.' );
		}
		$table = $this->getDbTable ();
		$select = $table->select ();
		$select->where ( $this->getDbTable ()->getPrimaryKey () . '=?', $id );
		$select->from ( $this->getDbTable () );
		$result = $this->extend ( $table->fetchAll ( $select ) );
		if ($result) {
			return $result [0];
		} else {
			return false;
		}
	}

}